home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / packer / pack / xpkdisk / devio.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  24KB  |  1,006 lines

  1. /*-
  2.  * DEVIO.C
  3.  *
  4.  * The xpkdisk.device code that does the real work.
  5.  *
  6.  * $Id: devio.c,v 1.3 1993/11/08 13:11:15 Rhialto Rel $
  7.  * $Log: devio.c,v $
  8.  * Revision 1.3  1993/11/08  13:11:15  Rhialto
  9.  * Add RCS tags.
  10.  *
  11.  *
  12.  * This code is (C) Copyright 1989-1993 by Olaf Seibert. All rights reserved.
  13.  * May not be used or copied without a licence.
  14. -*/
  15.  
  16. #include <string.h>
  17. #include <stdio.h>
  18. #include "xpkdisk.h"
  19. #if NOXPK
  20. #define XPK_MARGIN  0
  21. #else
  22. #include <libraries/xpk.h>
  23. #endif
  24.  
  25. /*#undef DEBUG            */
  26. #ifdef DEBUG
  27. #   include "syslog.h"
  28. #else
  29. #   define    debug(x)
  30. #endif
  31.  
  32. Prototype void UnitSeglist(void);
  33.  
  34. Prototype void CMD_Read(struct IOStdReq *ioreq, UNIT *unit);
  35. Prototype void CMD_Write(struct IOStdReq *ioreq, UNIT *unit);
  36. Prototype void TD_Format(struct IOStdReq *ioreq, UNIT *unit);
  37. Prototype void CMD_Reset(struct IOStdReq *ioreq, UNIT *unit);
  38. Prototype void CMD_Update(struct IOStdReq *ioreq, UNIT *unit);
  39. Prototype void CMD_Clear(struct IOStdReq *ioreq, UNIT *unit);
  40. Prototype void TD_Seek(struct IOStdReq *ioreq, UNIT *unit);
  41. Prototype void TD_Changenum(struct IOStdReq *ioreq, UNIT *unit);
  42. Prototype void TD_Addchangeint(struct IOStdReq *ioreq, UNIT *unit);
  43. Prototype void TD_Remchangeint(struct IOStdReq *ioreq, UNIT *unit);
  44. Prototype void TD_Getgeometry(struct IOStdReq *ioreq, UNIT *unit);
  45. Prototype void TD_Motor(struct IOStdReq *ioreq, UNIT *unit);
  46. Prototype void TD_Remove(struct IOStdReq *ioreq, UNIT *unit);
  47. Prototype void TD_Protstatus(struct IOStdReq *ioreq, UNIT *unit);
  48. Prototype void TD_Changestate(struct IOStdReq *ioreq, UNIT *unit);
  49. Prototype void TD_Rawread(struct IOStdReq *ioreq, UNIT *unit);
  50. Prototype void TD_Rawwrite(struct IOStdReq *ioreq, UNIT *unit);
  51. Prototype void TD_Getdrivetype(struct IOStdReq *ioreq, UNIT *unit);
  52. Prototype void TD_Getnumtracks(struct IOStdReq *ioreq, UNIT *unit);
  53. Prototype void TD_Eject(struct IOStdReq *ioreq, UNIT *unit);
  54. Prototype void TD_(struct IOStdReq *ioreq, UNIT *unit);
  55.  
  56. Prototype int DevInit(DEV *dev);
  57. Prototype int DevCloseDown(DEV *dev);
  58. Prototype UNIT *UnitInit(DEV *dev, ulong UnitNr);
  59. Prototype int UnitCloseDown(struct IOStdReq *ioreq, DEV *dev, UNIT *unit);
  60.  
  61. struct DosLibrary   *DOSBase;
  62. struct Library        *XpkBase;
  63. struct IntuitionBase *IntuitionBase;
  64.  
  65. /* ------------------------------------------------------------------------- */
  66.  
  67. void           *
  68. GetHead(struct MinList *list)
  69. {
  70.     if ((void *) list->mlh_Head != (void *) &list->mlh_Tail)
  71.     return list->mlh_Head;
  72.     return NULL;
  73. }
  74.  
  75. void           *
  76. GetTail(struct MinList *list)
  77. {
  78.     if ((void *) list->mlh_Head != (void *) &list->mlh_Tail)
  79.     return list->mlh_TailPred;
  80.     return NULL;
  81. }
  82.  
  83. Prototype long min(long a, long b);
  84. long
  85. min(long a, long b)
  86. {
  87.     return a < b? a: b;
  88. }
  89.  
  90. /* ------------------------------------------------------------------------- */
  91.  
  92. struct CacheTrack {
  93.     struct MinNode  trk_Node;
  94.     short        trk_Number;
  95.     ushort        trk_Refcount;
  96.     int         trk_Size;
  97.     byte        trk_Data[0];
  98. };
  99.  
  100. #define TRK_DIRTY   0x8000    /* Bit in trk_Refcount */
  101.  
  102. static const char Directory[] = XPKDISKDIR "Unit%x";
  103.  
  104. int
  105. ReadOnly(UNIT *unit)
  106. {
  107.     __aligned struct InfoData infodata;
  108.     BPTR        fl;
  109.  
  110.     if (fl = Lock(XPKDISKDIR, SHARED_LOCK)) {
  111.     if (Info(fl, &infodata)) {
  112.         unit->xu_ReadOnly = (infodata.id_DiskState != ID_VALIDATED);
  113.     }
  114.     UnLock(fl);
  115.     }
  116.     return unit->xu_ReadOnly;
  117. }
  118.  
  119. Prototype int MakeDirectory(UNIT *unit);
  120.  
  121. int
  122. MakeDirectory(UNIT *unit)
  123. {
  124.     char        dirname[32];
  125.     BPTR        fl;
  126.  
  127.     sprintf(dirname, Directory, unit->xu_UnitNr);
  128.     fl = Lock(dirname, SHARED_LOCK);
  129.     if (fl == 0) {
  130.     if (fl = CreateDir(dirname)) {
  131.         UnLock(fl);         /* exclusive locks not invited */
  132.         fl = Lock(dirname, SHARED_LOCK);
  133.     }
  134.     }
  135.     debug(("New currentdir: %x\n", fl));
  136.     if (fl)
  137.     fl = CurrentDir(fl);
  138.     debug(("Old currentdir: %x\n", fl));
  139.     if (fl)
  140.     UnLock(fl);
  141.     if (!ReadOnly(unit))
  142.     MakeSubDirs(0, unit->xu_NumTracks - 1);
  143.     return (int)fl;
  144. }
  145.  
  146. /* ------------------------------------------------------------------------- */
  147.  
  148. long
  149. ReadTrack(UNIT *unit, struct CacheTrack *trk)
  150. {
  151.     char        filename[40];
  152.     long        res = -1;
  153. #if NOXPK
  154.     BPTR        fh;
  155. #endif
  156.  
  157. #if 0
  158.     if (trk->trk_Number >= unit->xu_NumTracks) {
  159.     unit->xu_NumTracks = trk->trk_Number + 1;
  160.     MakeSubDirs(trk->trk_Number, trk->trk_Number);
  161.     }
  162. #endif
  163.     NewName(filename, trk->trk_Number);
  164.     debug(("ReadTrack: Open %s\n", filename));
  165. #if NOXPK
  166.     if (fh = Open(filename, MODE_OLDFILE)) {
  167.     debug(("ReadTrack: Open %s succeeded\n", filename));
  168.     res = Read(fh, trk->trk_Data, unit->xu_TrackLen);
  169.     if (res >= 0 && res < unit->xu_TrackLen) {
  170.         memset(trk->trk_Data + res, 0, unit->xu_TrackLen - res);
  171.     }
  172.     Close(fh);
  173. #else
  174.     debug(("Call XpkUnpackTags\n"));
  175.     res = XpkUnpackTags(
  176.         XPK_OutBuf, trk->trk_Data,
  177.         XPK_OutBufLen, unit->xu_TrackLen + XPK_MARGIN,
  178.         XPK_InName, filename,
  179.         XPK_PassThru, 1,
  180.         TAG_DONE);
  181.     if (res == XPKERR_OK) {
  182. #endif
  183.     } else {
  184.     debug(("ReadTrack: Open %s failed\n", filename));
  185.     memset(trk->trk_Data, 0, unit->xu_TrackLen);
  186.     }
  187.     debug(("res = %d\n", res));
  188.     return res;
  189. }
  190.  
  191. long
  192. WriteTrack(UNIT *unit, struct CacheTrack *trk)
  193. {
  194.     char        filename[40];
  195.     long        res = -1;
  196.  
  197.     if (trk->trk_Number >= unit->xu_NumTracks) {
  198.     unit->xu_NumTracks = trk->trk_Number + 1;
  199.     MakeSubDirs(trk->trk_Number, trk->trk_Number);
  200.     }
  201.  
  202.     if ((unit->xu_CacheFlags & CACHEF_SAFEWRITE) && !CheckRipcord(unit)) {
  203.     debug(("Set WriteErr\n"));
  204.     unit->xu_WriteErr = TDERR_TooFewSecs;
  205.     return -1;
  206.     }
  207.  
  208.     NewName(filename, trk->trk_Number);
  209.     debug(("WriteTrack: %s\n", filename));
  210. #if !NOXPK
  211.     debug(("Call XpkPackTags %s\n", unit->xu_XPKPackMethod));
  212.     res = XpkPackTags(
  213.         XPK_InBuf, trk->trk_Data,
  214.         XPK_InLen, unit->xu_TrackLen,
  215.         XPK_OutName, filename,
  216.         XPK_PackMethod, unit->xu_XPKPackMethod,
  217.         XPK_StepDown, 1,
  218.         TAG_DONE);
  219.     if (res == XPKERR_OK)
  220.     trk->trk_Refcount &= ~TRK_DIRTY;
  221.     else
  222. #endif
  223.     {
  224.     BPTR        fh;
  225.  
  226.     if (fh = Open(filename, MODE_NEWFILE)) {
  227.         debug(("WriteTrack: Open %s succeded\n", filename));
  228.         res = Write(fh, trk->trk_Data, unit->xu_TrackLen);
  229.         if (res == unit->xu_TrackLen) {
  230.         trk->trk_Refcount &= ~TRK_DIRTY;
  231.         } else
  232.         res = -1;
  233.         Close(fh);
  234.     }
  235.     }
  236.     debug(("res = %d\n", res));
  237.     return res;
  238. }
  239.  
  240.  
  241. /*
  242.  * Find a specific track. The cache list is a Least Recently Used stack:
  243.  * Put it on the head of the cache list. So if it is not used anymore in a
  244.  * long time, it bubbles to the end of the list, getting a higher chance
  245.  * of being trashed for re-use.
  246.  */
  247.  
  248. struct CacheTrack *
  249. FindTrackByNumber(UNIT *unit, int number)
  250. {
  251.     struct CacheTrack *trk;
  252.     struct MinNode  *nexttrk;
  253.  
  254.     debug(("FindTrackByNumber %ld ", (long)number));
  255.  
  256.     trk = unit->xu_Cache.LRUList.mlh_Head;
  257.     while (nexttrk = trk->trk_Node.mln_Succ) {
  258.     if (trk->trk_Number == number) {
  259.         debug((" (%lx) %lx\n", (long)trk->trk_Refcount, trk));
  260.         Remove((struct Node *)&trk->trk_Node);
  261.         AddHead((struct List *)&unit->xu_Cache.LRUList,
  262.             (struct Node *)&trk->trk_Node);
  263.         return trk;
  264.     }
  265.     debug(("cache %ld %lx; ", (long)trk->trk_Number, trk));
  266.     trk = nexttrk;
  267.     }
  268.  
  269.     return NULL;
  270. }
  271.  
  272. /*
  273.  * Get a fresh cache buffer. If we are allowed more cache, we just
  274.  * allocate memory. Otherwise, we try to find a currently unused buffer.
  275.  * We start looking at the end of the list, which is the bottom of the LRU
  276.  * stack. If that fails, allocate more memory anyway. Not that is likely
  277.  * anyway, since we currently lock only one track at a time.
  278.  */
  279.  
  280. struct CacheTrack *
  281. NewCacheTrack(UNIT *unit)
  282. {
  283.     struct CacheTrack *trk;
  284.     struct MinNode  *nexttrk;
  285.  
  286.     debug(("NewCacheTrack\n"));
  287.  
  288. #define SIZE (sizeof(*trk) + unit->xu_TrackLen + XPK_MARGIN)
  289.  
  290.     if (unit->xu_CurrentCache < unit->xu_MaxCache) {
  291.     if (trk = AllocMem(SIZE, MEMF_ANY)) {
  292.         goto add;
  293.     }
  294.     }
  295.     for (trk = unit->xu_Cache.LRUList.mlh_TailPred;
  296.      nexttrk = trk->trk_Node.mln_Pred;
  297.      trk = nexttrk) {
  298.     if ((unit->xu_CurrentCache >= unit->xu_MaxCache) &&
  299.         (trk->trk_Refcount == TRK_DIRTY)) {
  300.         debug(("NewCachetrktor: dump dirty trk %d\n", trk->trk_Number));
  301.         FreeCacheTrack(unit, trk);       /* Also writes it to disk */
  302.         continue;
  303.     }
  304.     if (trk->trk_Refcount == 0) {   /* Implies not TRK_DIRTY */
  305.         debug(("NewCachetrk: re-use clean trk %d\n", trk->trk_Number));
  306.         Remove((struct Node *)&trk->trk_Node);
  307.         goto move;
  308.     }
  309.     }
  310.  
  311.     trk = AllocMem(SIZE, MEMF_ANY);
  312.  
  313.     if (trk) {
  314. add:
  315.     trk->trk_Size = SIZE;
  316.     unit->xu_CurrentCache++;
  317. move:
  318.     AddHead((struct List *) &unit->xu_Cache.LRUList,
  319.         (struct Node *) &trk->trk_Node);
  320.     }
  321.  
  322.     debug(("NewCacheTrack: %lx\n", trk));
  323.     return trk;
  324. #undef SIZE
  325. }
  326.  
  327. /*
  328.  * Dispose a cached track, even if it has a non-zero refcount. If it is
  329.  * dirty, write it out.
  330.  * If an error occurs, stop.
  331.  */
  332. Prototype int FreeCacheTrack(UNIT *unit, struct CacheTrack *trk);
  333. int
  334. FreeCacheTrack(UNIT *unit, struct CacheTrack *trk)
  335. {
  336.     int         error;
  337.  
  338.     debug(("FreeCachetrk %ld\n", (long)trk->trk_Number));
  339.  
  340.     if (trk->trk_Refcount & ~TRK_DIRTY) {
  341.     debug(("\n\t*** PANIC!!! Refcount not 0 (%x) !!! ***\n\n", trk->trk_Refcount));
  342.     trk->trk_Refcount &= TRK_DIRTY;
  343.     }
  344.  
  345.     if (trk->trk_Refcount & TRK_DIRTY) {
  346.     error = WriteTrack(unit, trk);
  347.     } else
  348.     error = 0;
  349.  
  350.     if (error == 0) {
  351.     Remove((struct Node *)&trk->trk_Node);
  352.     FreeMem(trk, trk->trk_Size);
  353.     unit->xu_CurrentCache--;
  354.     }
  355.  
  356.     return error;
  357. }
  358.  
  359. /*
  360.  * Create an empty cache
  361.  */
  362.  
  363. void
  364. InitCache(UNIT *unit)
  365. {
  366.     NewList((struct List *)&unit->xu_Cache.LRUList);
  367.     unit->xu_MaxCache = MAX_CACHE;
  368.     unit->xu_CurrentCache = 0;
  369.     unit->xu_CacheDirty = 0;
  370.     unit->xu_CacheFlags = CACHE_FLAGS;
  371.     unit->xu_CacheTimeout = CACHE_TIMEOUT;
  372. }
  373.  
  374. /*
  375.  * Dispose all cached tracks, possibly writing them to disk.
  376.  * If an error occurs, stop.
  377.  */
  378.  
  379. int
  380. FreeCacheList(UNIT *unit)
  381. {
  382.     struct CacheTrack *trk;
  383.     int         error;
  384.  
  385.     debug(("FreeCacheList, %ld\n", (long)unit->xu_CurrentCache));
  386.     while ((trk = GetHead(&unit->xu_Cache.LRUList)) &&
  387.        (error = FreeCacheTrack(unit, trk)) == 0)
  388.     ;
  389.  
  390.     if (error == 0) {
  391.     debug(("Clear WriteErr\n"));
  392.     unit->xu_WriteErr = 0;
  393.     }
  394.     return error;
  395. }
  396.  
  397. struct CacheTrack *
  398. GetTrack(struct IOStdReq *ioreq, int track)
  399. {
  400.     UNIT       *unit;
  401.     struct CacheTrack *trk;
  402.  
  403.     debug(("GetTrack %ld\n", (long)track));
  404.     unit = (UNIT *) ioreq->io_Unit;
  405.  
  406.     if (trk = FindTrackByNumber(unit, track)) {
  407.     trk->trk_Refcount++;
  408.     return trk;
  409.     }
  410.  
  411.     if (trk = NewCacheTrack(unit)) {
  412.     trk->trk_Refcount = 1;
  413.     trk->trk_Number = track;
  414.     ReadTrack(unit, trk);
  415.     return trk;
  416.     }
  417.  
  418.     return NULL;
  419. }
  420.  
  421. void
  422. MarkTrackDirty(UNIT *unit, struct CacheTrack *trk)
  423. {
  424.     if (trk) {
  425.     trk->trk_Refcount |= TRK_DIRTY;
  426.     unit->xu_CacheDirty = 1;
  427.     }
  428. }
  429.  
  430. /*
  431.  * Unlock a cached track. When the usage count drops to zero, which
  432.  * implies it is not dirty, and we are over our cache quota, the sector is
  433.  * freed. Otherwise we keep it for re-use.
  434.  */
  435.  
  436. void
  437. FreeTrack(UNIT *unit, struct CacheTrack *trk)
  438. {
  439.     if (trk) {
  440.     --trk->trk_Refcount;
  441.     /*
  442.      * If we need to dump cache then dump some long-unused track.
  443.      */
  444.     while (unit->xu_CurrentCache > unit->xu_MaxCache &&
  445.         (trk = GetTail(&unit->xu_Cache.LRUList)) &&
  446.         (trk->trk_Refcount & ~TRK_DIRTY) == 0) {
  447.         debug(("Freetrk: dump %s trk %d\n",
  448.             (trk->trk_Refcount & TRK_DIRTY)? "dirty" : "clean",
  449.             trk->trk_Number));
  450.         FreeCacheTrack(unit, trk);
  451.     }
  452.     }
  453. }
  454.  
  455. /*
  456.  * Decide if we must do an update.
  457.  */
  458.  
  459. int
  460. Internal_Update(UNIT *unit)
  461. {
  462.     struct CacheTrack *trk;
  463.     struct MinNode *nexttrk;
  464.     int         error = 0;
  465.  
  466.     debug(("Internal_Update\n"));
  467.     /* Is the cache dirty? */
  468.     if (unit->xu_CacheDirty == 0) {
  469.     debug(("Cache not dirty\n"));
  470.     goto cleartriggers;
  471.     }
  472.  
  473.     /* Did we get a CMD_UPDATE, if required? */
  474.     if ((unit->xu_CacheFlags & (CACHEF_CMDUPDATE|CACHEF_GOTCMDUPD)) == CACHEF_CMDUPDATE) {
  475.     debug(("No required UPDATE\n"));
  476.     return 0;
  477.     }
  478.  
  479.     /* Did we get a timeout, if required? */
  480.     if ((unit->xu_CacheFlags & (CACHEF_DELAY|CACHEF_GOTTIMEOUT)) == CACHEF_DELAY) {
  481.     debug(("No required TIMEOUT\n"));
  482.     return 0;
  483.     }
  484.  
  485.     for (trk = unit->xu_Cache.LRUList.mlh_TailPred;
  486.      nexttrk = trk->trk_Node.mln_Pred;
  487.      trk = nexttrk) {
  488.     if (trk->trk_Refcount & TRK_DIRTY) {
  489.         if (error = WriteTrack(unit, trk))
  490.         goto end;    /* Don't clear update conditions */
  491.     }
  492.     }
  493.  
  494.     unit->xu_CacheDirty = 0;
  495.     if (error == 0) {
  496.     debug(("Clear WriteErr\n"));
  497.     unit->xu_WriteErr = 0;
  498.     }
  499. cleartriggers:
  500.     unit->xu_CacheFlags &= ~(CACHEF_GOTCMDUPD | CACHEF_GOTTIMEOUT);
  501. end:
  502.     return error;
  503. }
  504.  
  505. /* ------------------------------------------------------------------------- */
  506.  
  507. /*
  508.  * Read zero or more sectors from the disk and copy them into the user's
  509.  * buffer.
  510.  */
  511.  
  512. void
  513. CMD_Read(struct IOStdReq *ioreq, UNIT *unit)
  514. {
  515.     int         track;
  516.     byte       *userbuf;
  517.     long        length;
  518.     long        offset;
  519.     struct CacheTrack *trk;
  520.     int         error;
  521.  
  522.     debug(("CMD_Read "));
  523.     userbuf = (byte *) ioreq->io_Data;
  524.     length = ioreq->io_Length;
  525.     offset = ioreq->io_Offset;
  526.     debug(("userbuf %08lx off %ld len %ld\n", userbuf, offset, length));
  527.  
  528.     track = offset / unit->xu_TrackLen;
  529.     offset = offset % unit->xu_TrackLen;
  530.     debug(("Tr=%ld Offset=%ld\n", (long)track, (long)offset));
  531.  
  532.     ioreq->io_Actual = length;
  533.     error = TDERR_NoError;
  534.  
  535.     if (length <= 0)
  536.     goto end;
  537.  
  538.     if (offset != 0) {
  539.     /* Handle non-track  part first */
  540.     ulong        l;
  541.  
  542.     trk = GetTrack(ioreq, track);
  543.     if (trk == NULL) {
  544.         error = TDERR_NoSecHdr;
  545.         goto end;
  546.     }
  547.     l = min(length, unit->xu_TrackLen - offset);
  548.  
  549.     CopyMem(trk->trk_Data + offset, userbuf, l);
  550.     userbuf += l;
  551.     length -= l;
  552.     track++;
  553.     FreeTrack(unit, trk);
  554.     }
  555.  
  556.     while (length > 0) {
  557.     ulong        l;
  558.  
  559.     trk = GetTrack(ioreq, track);
  560.     if (trk == NULL) {
  561.         error = TDERR_NoSecHdr;
  562.         goto end;
  563.     }
  564.     l = min(length, unit->xu_TrackLen);
  565.  
  566.     CopyMem(trk->trk_Data, userbuf, l);
  567.     userbuf += l;
  568.     length -= l;
  569.     track++;
  570.     FreeTrack(unit, trk);
  571.     }
  572.  
  573. end:
  574.     ioreq->io_Error = error;
  575.     if (error != TDERR_NoError)
  576.     ioreq->io_Actual = 0;
  577.     TermIO(ioreq);
  578. }
  579.  
  580. void
  581. CMD_Write(struct IOStdReq *ioreq, UNIT *unit)
  582. {
  583.     int         track;
  584.     byte       *userbuf;
  585.     long        length;
  586.     long        offset;
  587.     struct CacheTrack *trk;
  588.     int         error;
  589.  
  590.     debug(("CMD_Write "));
  591.  
  592.     if (unit->xu_ReadOnly) {
  593.     error = TDERR_WriteProt;
  594.     goto end;
  595.     }
  596.  
  597.     userbuf = (byte *) ioreq->io_Data;
  598.     length = ioreq->io_Length;
  599.     offset = ioreq->io_Offset;
  600.     debug(("userbuf %08lx off %ld len %ld\n", userbuf, offset, length));
  601.  
  602.     track = offset / unit->xu_TrackLen;
  603.     offset = offset % unit->xu_TrackLen;
  604.     debug(("Tr=%ld Offset=%ld\n", (long)track, (long)offset));
  605.  
  606.     ioreq->io_Actual = length;
  607.     error = TDERR_NoError;
  608.  
  609.     if (length <= 0)
  610.     goto end;
  611.  
  612.     if (offset != 0) {
  613.     /* Handle non-track aligned part first */
  614.     ulong        l;
  615.  
  616.     trk = GetTrack(ioreq, track);
  617.     if (trk == NULL) {
  618.         error = TDERR_NoSecHdr;
  619.         goto end;
  620.     }
  621.     l = min(length, unit->xu_TrackLen - offset);
  622.  
  623.     CopyMem(userbuf, trk->trk_Data + offset, l);
  624.     userbuf += l;
  625.     length -= l;
  626.     track++;
  627.     MarkTrackDirty(unit, trk);
  628.     FreeTrack(unit, trk);
  629.     }
  630.  
  631.     while (length > 0) {
  632.     ulong        l;
  633.  
  634.     trk = GetTrack(ioreq, track);
  635.     if (trk == NULL) {
  636.         error = TDERR_NoMem;
  637.         goto end;
  638.     }
  639.     l = min(length, unit->xu_TrackLen);
  640.  
  641.     CopyMem(userbuf, trk->trk_Data, l);
  642.     userbuf += l;
  643.     length -= l;
  644.     track++;
  645.     MarkTrackDirty(unit, trk);
  646.     FreeTrack(unit, trk);
  647.     }
  648.  
  649. end:
  650.     if (error == 0 && unit->xu_WriteErr != 0) {
  651.     /* Propagate earlier write error(s) of previous tracks */
  652.     debug(("Use & Clear WriteErr\n"));
  653.     error = unit->xu_WriteErr;
  654.     unit->xu_WriteErr = 0;
  655.     }
  656.     ioreq->io_Error = error;
  657.     if (error != TDERR_NoError)
  658.     ioreq->io_Actual = 0;
  659.     TermIO(ioreq);
  660.  
  661.     StartTimeout(unit);
  662. }
  663.  
  664. void
  665. TD_Format(struct IOStdReq *ioreq, UNIT *unit)
  666. {
  667.     debug(("CMD_Format "));
  668.     /* keep it simple for now */
  669.     CMD_Write(ioreq, unit);
  670. }
  671.  
  672. void
  673. CMD_Reset(struct IOStdReq *ioreq, UNIT *unit)
  674. {
  675.     debug(("CMD_Reset\n"));
  676. #if 0
  677.     FreeCacheList(unit);        /* Just to be sure */
  678. #endif
  679.     MagicInit(unit);            /* Get mountlist info and user prefs */
  680.     if (!ReadOnly(unit) && (unit->xu_CacheFlags & CACHEF_SAFEWRITE))
  681.     MakeRipcord(unit);
  682.     TermIO(ioreq);
  683. }
  684.  
  685. void
  686. CMD_Update(struct IOStdReq *ioreq, UNIT *unit)
  687. {
  688.     debug(("CMD_Update\n"));
  689.     unit->xu_CacheFlags |= CACHEF_GOTCMDUPD;
  690.     StartTimeout(unit);
  691.     ioreq->io_Error = Internal_Update(unit);
  692.     TermIO(ioreq);
  693. }
  694.  
  695. void
  696. CMD_Clear(struct IOStdReq *ioreq, UNIT *unit)
  697. {
  698.     debug(("CMD_Clear\n"));
  699.     ioreq->io_Error = FreeCacheList(unit);
  700.     TermIO(ioreq);
  701. }
  702.  
  703. void
  704. TD_Motor(struct IOStdReq *ioreq, UNIT *unit)
  705. {
  706.     debug(("TD_Motor\n"));
  707.     ioreq->io_Actual = 1;    /* Motor is running */
  708.     TermIO(ioreq);
  709. }
  710.  
  711. void
  712. TD_Return0(struct IOStdReq *ioreq, UNIT *unit)
  713. {
  714.     debug(("TD_Seek, TD_Changenum, TD_Changestate\n"));
  715.     ioreq->io_Actual = 0;
  716.     TermIO(ioreq);
  717. }
  718.  
  719. void
  720. TD_Protstatus(struct IOStdReq *ioreq, UNIT *unit)
  721. {
  722.     debug(("TD_Protstatus\n"));
  723.     ioreq->io_Actual = ReadOnly(unit);
  724.     TermIO(ioreq);
  725. }
  726.  
  727. void
  728. TD_Getnumtracks(struct IOStdReq *ioreq, UNIT *unit)
  729. {
  730.     debug(("TD_Getnumtracks\n"));
  731.     ioreq->io_Actual = unit->xu_NumTracks;  /* a guess */
  732.     TermIO(ioreq);
  733. }
  734.  
  735. /*
  736.  * Handle disk change interrupts. However, our disks never get taken
  737.  * out of their drives.
  738.  */
  739.  
  740. void
  741. TD_Addchangeint(struct IOStdReq *ioreq, UNIT *unit)
  742. {
  743.     Enqueue((struct List *)&unit->xu_ChangeIntList, &ioreq->io_Message.mn_Node);
  744.     ioreq->io_Flags &= ~IOF_QUICK;    /* So we call ReplyMsg instead of
  745.                      * TermIO */
  746.     /* Note no TermIO */
  747. }
  748.  
  749. void
  750. TD_Remchangeint(struct IOStdReq *ioreq, UNIT *unit)
  751. {
  752.     struct IOStdReq *intreq;
  753.  
  754.     intreq = (struct IOStdReq *) ioreq->io_Data;
  755.     Remove(&intreq->io_Message.mn_Node);
  756.     ReplyMsg(&intreq->io_Message);      /* Quick bit always cleared */
  757.     ioreq->io_Error = 0;
  758.     TermIO(ioreq);
  759. }
  760.  
  761. void
  762. TD_Getgeometry(struct IOStdReq *ioreq, UNIT *unit)
  763. {
  764. #ifdef TD_GETGEOMETRY
  765.     struct DriveGeometry *dg;
  766.     short numtracks;
  767.  
  768.     debug(("TD_Getgeometry\n"));
  769.     dg = (struct DriveGeometry *)ioreq->io_Data;
  770.  
  771.     numtracks = unit->xu_NumTracks;
  772.     dg->dg_SectorSize = XD_BPS;
  773.  
  774.     dg->dg_TotalSectors = XD_SPT * numtracks;
  775.  
  776.     dg->dg_Cylinders = numtracks;
  777.     dg->dg_CylSectors = XD_SPT;
  778.  
  779.     dg->dg_Heads = 1;
  780.     dg->dg_TrackSectors = XD_SPT;
  781.  
  782.     dg->dg_BufMemType = MEMF_PUBLIC;
  783.     dg->dg_DeviceType = DG_DIRECT_ACCESS;
  784.     dg->dg_Flags = 0;        /* not DGF_REMOVABLE */
  785. #else
  786.     ioreq->io_Error = IOERR_NOCMD;
  787. #endif
  788. }
  789.  
  790. /* ------------------------------------------------------------------------- */
  791.  
  792. #define ROUNDS        2
  793.  
  794. void
  795. StartTimer(UNIT *unit)
  796. {
  797.     WaitIO(&unit->xu_TimeReq.tr_node);
  798.     unit->xu_TimeReq.tr_node.io_Command = TR_ADDREQUEST;
  799.     unit->xu_TimeReq.tr_time.tv_secs = unit->xu_CacheTimeout / ROUNDS;
  800.     unit->xu_TimeReq.tr_time.tv_micro =
  801.             (unit->xu_CacheTimeout % ROUNDS) * (1000000 / ROUNDS);
  802.     SendIO(&unit->xu_TimeReq.tr_node);
  803. }
  804.  
  805. Prototype void PollTimer(UNIT *unit);
  806. void
  807. PollTimer(UNIT *unit)
  808. {
  809.     if (CheckIO(&unit->xu_TimeReq.tr_node)) {
  810.     if (--unit->xu_TimeoutCounter <= 0) {
  811.         unit->xu_CacheFlags |= CACHEF_GOTTIMEOUT;
  812.         (void)Internal_Update(unit);
  813.     } else {
  814.         StartTimer(unit);
  815.     }
  816.     }
  817. }
  818.  
  819. Prototype void StartTimeout(UNIT *unit);
  820.  
  821. void
  822. StartTimeout(UNIT *unit)
  823. {
  824.     unit->xu_TimeoutCounter = ROUNDS;
  825.     if (CheckIO(&unit->xu_TimeReq.tr_node))
  826.     StartTimer(unit);
  827. }
  828.  
  829. int
  830. DevInit(DEV *dev)
  831. {
  832.     debug(("DevInit: open dos\n"));
  833.     DOSBase = OpenLibrary("dos.library", 0);
  834.  
  835.     debug(("done DevInit\n"));
  836.     return 1;            /* Initializing succeeded */
  837.  
  838. abort:
  839.     return DevCloseDown(dev);
  840. }
  841.  
  842. int
  843. DevCloseDown(dev)
  844. DEV           *dev;
  845. {
  846.     if (DOSBase) {
  847.     CloseLibrary((struct Library *)DOSBase);
  848.     DOSBase = NULL;
  849.     }
  850.     return 0;            /* Now unitialized */
  851. }
  852.  
  853. ulong
  854. InitMsgPort(struct MsgPort *p)
  855. {
  856.     p->mp_SigTask = FindTask(NULL);
  857.     p->mp_SigBit = AllocSignal(-1);
  858.     p->mp_Flags = PA_SIGNAL;
  859.     Forbid();
  860.     /*
  861.      * We must Forbid() here to prevent a race condition. That is also
  862.      * sufficient, since interrupts are not allowed to call BeginIO().
  863.      */
  864.     if (p->mp_MsgList.lh_Head == NULL)
  865.     NewList(&p->mp_MsgList);
  866.     Permit();
  867.  
  868.     return 1L << p->mp_SigBit;
  869. }
  870.  
  871. UNIT           *
  872. UnitInit(dev, UnitNr)
  873. DEV           *dev;
  874. ulong        UnitNr;
  875. {
  876.     UNIT       *unit;
  877.     struct Task    *task;
  878.     struct MsgPort *p;
  879.  
  880.     unit = AllocMem((long) sizeof (UNIT), MEMF_PUBLIC | MEMF_CLEAR);
  881.     if (unit == NULL)
  882.     return NULL;
  883.  
  884.     unit->xu_UnitNr = UnitNr;
  885.     /*
  886.      * Now create the Unit process. Remember that it won't start running
  887.      * since we are Forbid()den. But just to be sure, we Forbid() again.
  888.      */
  889.     debug(("call CreateProc %x (%x)\n",
  890.         MKBADDR(UnitSeglist), UnitSeglist));
  891.     Forbid();
  892.     p = CreateProc(DevName, TASKPRI, MKBADDR(UnitSeglist), TASKSTACK);
  893.     if (p == NULL) {
  894.     Permit();
  895.     debug(("*** No Unit process!!!\n"));
  896.     goto abort;
  897.     }
  898.     task = (struct Task *)(((char *)p) - offsetof(struct Process, pr_MsgPort));
  899.     task->tc_UserData = (APTR) unit;
  900.  
  901.     unit->xu_Port.mp_Flags = PA_IGNORE;
  902.     unit->xu_Port.mp_SigTask = task;
  903.     NewList(&unit->xu_Port.mp_MsgList);
  904.  
  905.     Permit();
  906.     debug(("task: %lx\n", task));
  907.  
  908.     return unit;
  909.  
  910. abort:
  911.     UnitCloseDown(NULL, dev, unit);
  912.     return NULL;
  913. }
  914.  
  915. Prototype ulong UnitInit2(UNIT *unit);
  916. ulong
  917. UnitInit2(UNIT *unit)
  918. {
  919.     ulong        waitmask;
  920.  
  921.     waitmask = InitMsgPort(&unit->xu_Port);
  922.     waitmask |= InitMsgPort(&unit->xu_TimerPort);
  923.  
  924.     unit->xu_TimeReq.tr_node.io_Message.mn_ReplyPort = &unit->xu_TimerPort;
  925.     if (OpenDevice("timer.device", UNIT_VBLANK, &unit->xu_TimeReq.tr_node, 0))
  926.     return 0;
  927.     unit->xu_TimeReq.tr_node.io_Flags = IOF_QUICK;
  928.  
  929.     NewList((struct List *)&unit->xu_ChangeIntList);
  930.     unit->xu_TrackLen = XD_TRACKLEN;
  931.     strncpy(unit->xu_XPKPackMethod, PACKING_METHOD, 9);
  932.     InitCache(unit);
  933.     MagicInit(unit);            /* Get mountlist info and user prefs */
  934.     MakeDirectory(unit);
  935.     if (!unit->xu_ReadOnly && (unit->xu_CacheFlags & CACHEF_SAFEWRITE))
  936.     MakeRipcord(unit);
  937.  
  938. #if !NOXPK
  939.     XpkBase = OpenLibrary("xpkmaster.library", 0);
  940.     if (XpkBase == NULL)
  941.     return 0;
  942. #endif
  943.     IntuitionBase = OpenLibrary("intuition.library", 33);
  944.     if (IntuitionBase == NULL)
  945.     return 0;
  946.  
  947.     return waitmask;
  948. }
  949.  
  950. Prototype void UnitCloseDown2(UNIT *unit);
  951. void
  952. UnitCloseDown2(UNIT *unit)
  953. {
  954.     /*
  955.      * There may still be dirty tracks due to delayed updates.
  956.      * If an error occurs while writing the tracks out, we currently
  957.      * lose the memory.
  958.      */
  959.     (void)FreeCacheList(unit);
  960.     {
  961.     struct IORequest *ioreq;
  962.     while (ioreq = RemHead((struct List *)&unit->xu_ChangeIntList)) {
  963.         ReplyMsg(&ioreq->io_Message);
  964.     }
  965.     }
  966.  
  967.     UnLock(CurrentDir(0));
  968.  
  969.     AbortIO(&unit->xu_TimeReq.tr_node);
  970.     WaitIO(&unit->xu_TimeReq.tr_node);
  971.     CloseDevice(&unit->xu_TimeReq.tr_node);
  972.     if (IntuitionBase)
  973.     CloseLibrary(IntuitionBase);
  974.     if (XpkBase)
  975.     CloseLibrary(XpkBase);
  976. }
  977.  
  978. int
  979. UnitCloseDown(struct IOStdReq *ioreq, DEV *dev, UNIT *unit)
  980. {
  981.     /*
  982.      * Get rid of the Unit's task. We know this is safe because the unit
  983.      * has an open count of zero, so it is 'guaranteed' not in use.
  984.      */
  985.  
  986.     if (unit->xu_Port.mp_SigTask) {
  987.     struct IORequest io;
  988.  
  989.     io.io_Message.mn_ReplyPort = (struct MsgPort *)FindTask(NULL);
  990.     io.io_Command = CMD_Die;
  991.     unit->xu_Flags &= ~UNITF_STOPPED;
  992.     debug(("Asking task to die\n"));
  993.     PutMsg(&unit->xu_Port, &io.io_Message);
  994.     do {
  995.         Wait(SIGF_SINGLE);
  996.         debug(("Someone exhaled...\n"));
  997.     } while (io.io_Message.mn_Node.ln_Type != NT_REPLYMSG);
  998.     debug(("That was the last gasp!\n"));
  999.     }
  1000.     FreeMem(unit, (long) sizeof (UNIT));
  1001.  
  1002.     return 0;            /* Now unitialized */
  1003. }
  1004.  
  1005. /* ------------------------------------------------------------------------- */
  1006.